from datetime import datetime
import os
import sentry_sdk
from fastapi import FastAPI
import uvicorn
from fastapi.routing import APIRoute
from starlette.middleware.cors import CORSMiddleware
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
from contextlib import asynccontextmanager
from app.api.main import api_router
from app.core.config import settings
from app.tasks import upload_daily_data

# 将标准 logging 重定向到 loguru
import logging
from loguru import logger


class InterceptHandler(logging.Handler):
    def emit(self, record):
        # 获取对应等级
        level = (
            logger.level(record.levelname).name
            if record.levelname in ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
            else "INFO"
        )
        frame, depth = logging.currentframe().f_back, 2
        while frame.f_code.co_filename == logging.__file__:
            frame = frame.f_back
            depth += 1
        logger.opt(depth=depth, exception=record.exc_info).log(
            level, record.getMessage()
        )


# 应用拦截
# ✅ 关键：先移除 root logger 所有 handler，再设置 InterceptHandler
logging.basicConfig(handlers=[InterceptHandler()], level=0)

# ✅ 为每个模块 logger 清除原有 handler，只保留 InterceptHandler
for name in [
    "uvicorn",
    "uvicorn.access",
    "uvicorn.error",
    "fastapi",
    "apscheduler",
    "httpx",
    "httpx.request",
]:
    logging.getLogger(name).handlers.clear()  # 🚫 清空原有 handler
    logging.getLogger(name).addHandler(InterceptHandler())  # ✅ 只加我们的
    logging.getLogger(name).propagate = False  # 🚫 防止向上传播到 root logger 造成重复


log_directory = "logs"
os.makedirs(log_directory, exist_ok=True)  # 确保日志目录存在

# 生成日志文件名，例如：app_2023-10-01.log
log_file = os.path.join(log_directory, f"app_{datetime.now().strftime('%Y-%m-%d')}.log")
logger.add(
    log_file,
    rotation="500 MB",  # 每 500MB 轮转一次新文件
    retention="10 days",  # 保留最近 10 天的日志文件
    level="INFO",  # 记录 INFO 级别及以上的日志
    format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} | {message}",
    enqueue=True,  # 异步写入，提高性能
)


def custom_generate_unique_id(route: APIRoute) -> str:
    return f"{route.tags[0]}-{route.name}"


if settings.SENTRY_DSN and settings.ENVIRONMENT != "local":
    sentry_sdk.init(dsn=str(settings.SENTRY_DSN), enable_tracing=True)


# 初始化调度器
scheduler = AsyncIOScheduler()


@asynccontextmanager
async def lifespan(app: FastAPI):
    # 启动时添加任务
    scheduler.add_job(
        upload_daily_data,
        CronTrigger(hour=23, minute=50),  # 每天 23:50 执行
        # CronTrigger(minute='*'),  # 每天 23:50 执行
        id="daily_upload",  # 任务ID，便于管理
        name="每日数据上传",
        replace_existing=True,  # 如果任务已存在，替换它
    )
    scheduler.start()
    logger.info("📅 定时任务已启动：每天 23:50 上传数据")

    yield  # FastAPI 运行中...

    # 关闭时停止调度器
    scheduler.shutdown()
    logger.info("🛑 定时任务已关闭")


app = FastAPI(
    title=settings.PROJECT_NAME,
    openapi_url=f"{settings.API_V1_STR}/openapi.json",
    generate_unique_id_function=custom_generate_unique_id,
    lifespan=lifespan,
)

# Set all CORS enabled origins
if settings.all_cors_origins:
    app.add_middleware(
        CORSMiddleware,
        # allow_origins=settings.all_cors_origins,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

app.include_router(api_router, prefix=settings.API_V1_STR)

if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
